using Cysharp.Threading.Tasks;
using M13.Math;
using M13.Utility;
using System.Collections.Generic;
using M13.DataStructure;
using UnityEngine;

namespace M13.Game.World
{
    public enum ChunkStatus
    {
        Persistent,//�־û������ݣ��������ڴ浵�������ļ��е�����
        Aggregated,//�ۼ������ݣ���������������ݴ����һ���ڴ���
        Specific,//��������ݣ���������������ݴ���ڸ��Ե���������
        Tangible,//ʵ�������ݣ������ѱ����ص�������
    }

    public class Region
    {
        /// <summary>
        /// ����ı����������
        /// </summary>
        public Vector2Int RegionCoord { get; private set; }

        /// <summary>
        /// �������������������
        /// </summary>
        public ChunkDataBoot[] ChunkDataBoots { get; private set; }

        /// <summary>
        /// ����������ڴ����ݣ��������ݵĵ���״̬
        /// </summary>
        public Dictionary<Vector2Int, Chunk> ChunkMap { get; private set; } = new Dictionary<Vector2Int, Chunk>();

        public ChunkStatus[] ChunkStatusMap { get; private set; } = new ChunkStatus[256];

        public RegionDataArray RegionDataArray { get; private set; }

        public Region() { }
        public Region(Vector2Int regionCoord, byte[] regionSingularCompressedData, byte[] regionBoot)
        {
            this.RegionCoord = regionCoord;
            RegionDataArray = new RegionDataArray(regionSingularCompressedData);
            ChunkDataBoots = DataBootSerializer.Deserializer(regionBoot).ToArray();

            for(int i = 0; i < ChunkStatusMap.Length; i++)
            {
                ChunkStatusMap[i] = ChunkStatus.Aggregated;
            }
        }


        public void Reutilization(Vector2Int regionCoord, byte[] regionSingularCompressedData, byte[] regionBoot)
        {
            this.RegionCoord = regionCoord;
            if(RegionDataArray == null)
            {
                RegionDataArray = new RegionDataArray(regionSingularCompressedData);
            }
            else RegionDataArray.Recycle(regionSingularCompressedData);
            ChunkDataBoots = DataBootSerializer.Deserializer(regionBoot).ToArray();

            for (int i = 0; i < ChunkStatusMap.Length; i++)
            {
                ChunkStatusMap[i] = ChunkStatus.Aggregated;
            }
        }

        public void AcquireChunkloadTesk(Vector2Int chunkLocalCoord)
        {
            if (ChunkMap.ContainsKey(chunkLocalCoord)) Debug.LogWarning($"������{RegionCoord}���ݵ�chunkmap���Ѿ�����������{chunkLocalCoord}����");

            int offset = M13Mathf.ChunkIndexOnRegion(chunkLocalCoord);
            //Debug.Log($"��������{regionCoord}, ��������{chunkLocalCoord}, ƫ��{offset}, ���鳤��{chunkDataBoots.Length}");
            ChunkDataBoot boot = ChunkDataBoots[offset];
            Chunk chunk = null;
            chunk = RegionDataArray.ConcretizeChunkData(chunkLocalCoord, boot);
            ChunkMap.Add(chunkLocalCoord, chunk);
            ChunkStatusMap[M13Mathf.ChunkIndexOnRegion(chunkLocalCoord)] = ChunkStatus.Specific;
        }

        public void AcquireChunkUnloadTesk(Vector2Int chunkLocalCoord)
        {
            ChunkDataBoot boot = RegionDataArray.MemorizeChunkData(ChunkMap[chunkLocalCoord]);
            ChunkMap.Remove(chunkLocalCoord);
            
            ChunkDataBoots[M13Mathf.ChunkIndexOnRegion(chunkLocalCoord)] = boot;
        }

        public void AcquireRegionUnloadTask()
        {
            List<Vector2Int> chunkCoords = new List<Vector2Int>();
            if (ChunkMap.Count != 0)
            {
                foreach(var chunk in ChunkMap)
                {
                    chunkCoords.Add(chunk.Key);
                }

                for(int i = 0; i < chunkCoords.Count; i++)
                {
                    AcquireChunkUnloadTesk(chunkCoords[i]);
                }
            }
        }

        public byte[] GetRegionBootData()
        {
            return DataBootSerializer.Serializer(ChunkDataBoots);
        }

        public ChunkDataBoot[] GetChunkDataBoots()
        {
            return ChunkDataBoots;
        }

        public bool HasLoadedChunk()
        {
            return ChunkMap.Count != 0;
        }

        public bool IsChunkLoaded(Vector2Int chunkLocalCoord)
        {
            return ChunkMap.ContainsKey(chunkLocalCoord);
        }

        
        public bool IsChunkOnThisRegion(Vector2Int chunkLocalCoord)
        {
            if (chunkLocalCoord.x >> 4 == RegionCoord.x && chunkLocalCoord.y >> 4 == RegionCoord.y) 
                return true;
            else return false;
        }

    }
}
